//#include <valarray>

#include "noguiInterface.h"


int curx;
int cury;
int curplayer;
int nplayers;
noguimap::menuoption opt;
#define numFChoice 6
string fleetoptions[] = {"move", "shoot", "split", "join",
    "transfer", "face"};
string normaloptions[] = {"new fleet", "end turn", "exit"};

//selftest++++++++++++++++++++++++
// set up a basic setup so that
// current llibraries can be
// tested
//--------------------------------
int noguimap::selftest() {
    //create a few ship protos
    //su1------
    Units::subunit* su1 = new Units::subunit(10, 5, 45, 10);
    su1->addBatery(Units::foreward, 10, 75, 0, 10, 1);
    //su2------
    Units::subunit* su2 = new Units::subunit(5, 5, 50, 10);
    su2->addBatery(Units::foreward, 10, 85, 0, 10, 1);
    //set up units
    //unitone---
    cout << "creating unit one..." << endl;
    Units::unit* unitone = new Units::unit();
    unitone->owner(0);
    cout << "created." << endl;
    unitone->name("Unit One");
    cout << "unit one named \"Unit One\"" << endl;
    unitone->add(su1, 400);
    unitone->add(su2, 1000);
    cout << "Ships added. - " << unitone->sunits() << endl;
    cout << "Moving...  ";
    unitone->resetAP();
    if (unitone->place(1, 5)) {
        cout << "Moved." << endl;
    } else {
        cout << "Move Failed" << endl;
    }
    cout << "Facing...  ";
    if (unitone->face(Units::right)) {
        cout << "Faced." << endl;
    } else {
        cout << "Face Failed." << endl;
    }
    unitone->resetAP();
    //unittwo---
    cout << "creating unit two..." << endl;
    Units::unit* unittwo = new Units::unit();
    unittwo->owner(1);
    cout << "created." << endl;
    unittwo->name("Unit Two");
    cout << "unit two named \"Unit Two\"" << endl;
    unittwo->add(su1, 400);
    unittwo->add(su2, 1000);
    cout << "Ships added. - " << unittwo->sunits() << endl;
    cout << "Moving..." << endl;
    unittwo->resetAP();
    if (unittwo->place(15, 5)) {
        cout << "Moved." << endl;
    } else {
        cout << "Move Failed" << endl;
    }
    cout << "Facing...  ";
    if (unittwo->face(Units::left)) {
        cout << "Faced." << endl;
    } else {
        cout << "Face Failed." << endl;
    }
    unittwo->resetAP();
    //begin

    nplayers = 2;
    curplayer = 0;

    cout << "go?";
    cin.get();
    initializeNcurses();
    controll();
    breakNcurses();
}
//================================
//initializeNcurses+++++++++++++++
// startup the ncurses
//--------------------------------
void noguimap::initializeNcurses() {
    curx = cury = 0;
    initscr();
    raw();
    keypad(stdscr, TRUE);
    cbreak();
    noecho();
}
//================================
//breakNcurses++++++++++++++++++++
// stop ncurses
//--------------------------------
void noguimap::breakNcurses() {
    endwin();
}
//================================
int noguimap::controll() {
    //set shit up
    initializeNcurses();
    noguimap::initializePlayers();
    //the main loop
    do {
        noguimap::map();
        opt = menu();
        switch (opt) {
            case movecmd:
                handleMove();
                break;
            case shoot:
                handleShoot();
                break;
            case split:
                handleSplit();
                break;
            case join:
                handleJoin();
                break;
            case transfer:
                handleTransfer();
                break;
            case face:
                handleFaceing();
                break;
            case endturn:
                curplayer++;
                if (curplayer >= nplayers) {
                    curplayer = 0;
                }
                Units::unitLib::staticLib()->resetAP();
                break;
        }
    } while (opt != noguimap::exit);
        breakNcurses();
}
void noguimap::initializePlayers() {
    //varblock-----
    int key = 0, xs, ys, numPs;
    string* names;
    string str = "";
    string printme = "How many players?";
    //=============
    getmaxyx(stdscr, ys, xs);
    clear();
    mvprintw(ys / 2, ((xs - printme.length()) / 2), "%s", printme.c_str());
    //get nums-----
    while (key != KEY_ENTER && key != '\n') {
        key = getch();
        if (key >= '0' && key <= '9') {
            str.push_back((char) key);
        } else if (key == KEY_BACKSPACE) {
            mvprintw(ys / 2 + 2, (xs / 2) - printme.length() + 1, " ");
            str.erase(--str.end());
        }
        mvprintw(ys / 2 + 2, (xs / 2), "%s", str.c_str());
    }
    numPs = atoi(str.c_str());
    if (numPs > Players::maxPlayers) numPs = Players::maxPlayers;
    if (numPs < 2) numPs = 2;
    names = new string[numPs];
    //get names----
    for (int i = 0; i < numPs; i++) {
        names[i] = "";
        key = 0;
        const int l = 24;
        clear();
        mvprintw(ys / 2, (xs - l) / 2, "Player %d\'s empire name: ", i + 1);
        while (key != KEY_ENTER && key != '\n') {
            key = getch();
            if (key == KEY_BACKSPACE) {
                names[i].erase(--str.end());
            } else if(key != KEY_ENTER && key != '\n'){
                names[i].push_back(key);
            }
            mvprintw(ys/2+1, (xs/2) - 2, "%s", names[i].c_str());
        }
        Players::playerLib::gStaticPlayerLib()->newPlayer(names[i]);
    }
    delete names;
}
int noguimap::map() {
    Units::unitLib* lib = Units::unitLib::staticLib();
    int x, y, key;
    getmaxyx(stdscr, y, x);
    do {
        clear();
        for (int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++) {
                if (lib->getUnit(i, j) != NULL) {
                    if (lib->getUnit(i, j)->owner() == curplayer) {
                        mvprintw(j, i, "o");

                    } else {
                        mvprintw(j, i, "u");
                    }
                    switch (lib->getUnit(i, j)->face()) {
                        case Units::up:
                            mvprintw(j - 1, i, "|");
                            break;
                        case Units::down:
                            mvprintw(j + 1, i, "|");
                            break;
                        case Units::left:
                            mvprintw(j, i - 1, "-");
                            break;
                        case Units::right:
                            mvprintw(j, i + 1, "-");
                            break;
                    }
                }
            }
        }
        mvprintw(cury, curx, "x");
        move(y - 1, x - 1);
        refresh();
        key = getch();
        switch (key) {
            case KEY_UP:
                cury--;
                break;
            case KEY_DOWN:
                cury++;
                break;
            case KEY_LEFT:
                curx--;
                break;
            case KEY_RIGHT:
                curx++;
                break;
        }
    } while ((key) != 10);
    return 0;
}
noguimap::menuoption noguimap::menu() {
    if (Units::unitLib::staticLib()->getUnit(curx, cury) != NULL) {
        return fleetmenu();
    }
    int x, y, choice, key;
    choice = key = 0;
    getmaxyx(stdscr, y, x);
    clear();

    do {
        for (int i = 0; i < 3; i++) {
            if (choice == i) attrset(A_STANDOUT);
            mvprintw((i * 3) + 1, (x - normaloptions[i].length()) / 2, "%s", normaloptions[i].c_str());
            attrset(A_NORMAL);
        }
        refresh();
        key = getch();
        switch (key) {
            case KEY_UP:
            case KEY_RIGHT:
                choice--;
                break;
            case KEY_DOWN:
            case KEY_LEFT:
                choice++;
                break;
        }
    } while (key != 10);

    switch (choice) {
        case 0:
            break;
        case 1:
            return endturn;
            break;
        case 2:
            return exit;
            break;
        default:
            return nocmd;
            break;
    }

}
noguimap::menuoption noguimap::fleetmenu() {
    //vars
    int x, y, choice, key;
    choice = key = 0;
    Units::unit* u = Units::unitLib::staticLib()->getUnit(curx, cury);
    std::map<Units::subunit*, int>::iterator iter = u->unititer();
    //draw
    getmaxyx(stdscr, y, x);
    clear();

    //print info
    mvprintw(2, 2, "Fleet: %s", u->name().c_str());
    mvprintw(4, 2, "Location: (%d, %d) -- AP: %d", u->posX(), u->posY(), u->apoints());
    for (int i = 6; i < y && (i - 6) / 2 < u->sunits(); i += 2, iter++) {
        mvprintw(i - 1, 2, "Subunit %d: %d", (i - 6) / 2, u->nums(iter->first));
        mvprintw(i, 2, "-- arm: %d shd: %d eva: %d",
                iter->first->arm(), iter->first->shd(), iter->first->eva());
    }

    //print commands
    if (u->owner() != curplayer) {
        getch();
        return nocmd;
    }
    do {
        for (int i = 0; i < numFChoice; i++) {
            if (choice == i) attrset(A_STANDOUT);
            mvprintw((i + 1) * 2, x - (fleetoptions[i].length() + 2), "%s", fleetoptions[i].c_str());
            attrset(A_NORMAL);
        }
        refresh();
        key = getch();
        switch (key) {
            case KEY_UP:
            case KEY_RIGHT:
                choice--;
                break;
            case KEY_DOWN:
            case KEY_LEFT:
                choice++;
                break;
        }
    } while (key != 10);
    switch (choice) {
        case 0:
            return movecmd;
            break;
        case 1:
            return shoot;
            break;
        case 2:
            return split;
            break;
        case 3:
            return join;
            break;
        case 4:
            return transfer;
            break;
        case 5:
            return face;
            break;
        default:
            break;
    }
    return nocmd;
}
void noguimap::handleMove() {
    int sx = curx;
    int sy = cury;
    map();
    int nx = curx;
    int ny = cury;
    Units::unit* u = Units::unitLib::staticLib()->getUnit(sx, sy);
    if (u != NULL) {
        u->move(nx, ny);
    }
}
void noguimap::handleShoot() {
    int sx = curx;
    int sy = cury;
    map();
    int nx = curx;
    int ny = cury;
    Units::unit* u = Units::unitLib::staticLib()->getUnit(sx, sy);
    Units::unit* targ = Units::unitLib::staticLib()->getUnit(nx, ny);
    if (u != NULL && targ != NULL) {
        mvprintw(2, 2, "!!");
        getch();
        Units::voley* v = u->shoot(nx, ny, Units::foreward);
        if (v == NULL) mvprintw(2, 5, "---");
        getch();
        targ->takeDamage(v);
    }
}
void noguimap::handleSplit() {
    //get pos's
    int sx = curx;
    int sy = cury;
    map();
    int nx = curx;
    int ny = cury;
    Units::unit* u = Units::unitLib::staticLib()->getUnit(sx, sy);
    Units::unit* nw = new Units::unit(u);
    nw->place(nx, ny);
    handleTransfer(sx, sy, nx, ny);
}
void noguimap::handleJoin() {
    int sx = curx;
    int sy = cury;
    map();
    int nx = curx;
    int ny = cury;
    Units::unitLib* ulib = Units::unitLib::staticLib();
    Units::unit* u1 = ulib->getUnit(sx, sy);
    Units::unit* u2 = ulib->getUnit(nx, ny);
    if (u1 == NULL || u2 == NULL) return;
    if (sx - nx > 1 || sx - sx < -1) return;
    if (sy - ny > 1 || sy - sy < -1) return;
    u2->recieve(u1);
}
void noguimap::handleTransfer() {
    int x = curx;
    int y = cury;
    map();
    int nx = curx;
    int ny = cury;
    handleTransfer(x, y, nx, ny);
}
void noguimap::handleTransfer(int x, int y, int nx, int ny) {
    Units::unit* src = Units::unitLib::staticLib()->getUnit(x, y);
    Units::unit* dest = Units::unitLib::staticLib()->getUnit(nx, ny);
    int nums[src->sunits()];
    for (int i = 0; i < src->sunits(); i++) {
        nums[i] = 0;
    }

    if (src != dest && src != NULL && dest != NULL) {
        clear();
        std::map<Units::subunit*, int>::iterator itr;
        int key = 0, choice = 0;
        do {
            itr = src->unititer();
            for (int i = 0; i < src->sunits(); i++, itr++) {
                if (choice == i) attrset(A_STANDOUT);
                mvprintw(i * 2, 2, "Subunit %d: %d \t\t%d", (i - 6) / 2, src->nums(itr->first), nums[i]);
                mvprintw((i * 2) + 1, 2, "-- arm: %d shd: %d eva: %d",
                        itr->first->arm(), itr->first->shd(), itr->first->eva());
                if (choice == i) attrset(A_NORMAL);
            }
            refresh();
            key = getch();
            switch (key) {
                case KEY_UP:
                    choice--;
                    break;
                case KEY_DOWN:
                    choice++;
                    break;
                case KEY_LEFT:
                    nums[choice] -= 5;
                    break;
                case KEY_RIGHT:
                    nums[choice] += 5;
                    break;
            }

        } while (key != 27);
        itr = src->unititer();
        for (int i = 0; i < src->sunits(); i++, itr++) {
            if (nums[i] > 0) {
                src->remove(itr->first, nums[i]);
                dest->add(itr->first, nums[i]);
            }
        }
    } else {
        mvprintw(0, 0, "could not get a fleet: f1 - %d, f2 - %d, NULL: %d", src, dest, NULL);
        getch();
    }
}
void noguimap::handleFaceing() {
    int sx = curx;
    int sy = cury;
    map();
    int nx = curx;
    int ny = cury;
    Units::unit* u = Units::unitLib::staticLib()->getUnit(sx, sy);
    u->face(u->relation(nx, ny));

}